package cn.hp.service.util;


import cn.hp.pojo.TblSysLog;
import cn.hp.service.syslog.SysLogService;
import cn.hp.util.SysLog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class LoggingTool {

    // 工具类 ——> service ——> dao
    @Autowired
    private SysLogService sysLogService ;

    // 配置切入点表达式  aop 要切入的方法 记录controller层的操作
    @Pointcut("execution(* *..controller.*.*(..))")
    public void fun(){}

//    日志记录表： 环绕通知
//      前置方法：operator、time、operation（自己去定义 自定义注解）、方法名、模块名
//      后置方法：执行时间 ( 方法的结束时间 - 开始时间 )
//      最终方法：结果

    // aop的底层设计模式 动态代理
    @Around("fun()")
    public Object around(ProceedingJoinPoint joinPoint ){
        // 进行日志记录的生成
        // 1.设置SysLog对象的数据
        TblSysLog tblSysLog = new TblSysLog() ;

        // 定义方法执行的开始时间
        long startTime = System.currentTimeMillis() ;
        // 2 设置时间
        tblSysLog.setTime(new Date());
        // 3 获取代理对象、拿到执行的方法、判断方法上是否包含自定义注解
        Object target = joinPoint.getTarget();
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取方法参数
        // 对签名的类型做处理
        if ( !(joinPoint.getSignature() instanceof MethodSignature)){
            throw  new RuntimeException("切入的方法不支持");
        }
        Class[] signature = ((MethodSignature)joinPoint.getSignature()).getParameterTypes();
        Method method  = null ;
        try {
            method = target.getClass().getMethod(methodName , signature);

        } catch (NoSuchMethodException e) {
            throw new RuntimeException("没有找到此方法");
        }
        // 反射的内容
        Object proceed = null ;
        try {
            // 拿到了 实际调用的方法
            // 4 判断这个方法中是否包含SysLog注解
            if (method.isAnnotationPresent(SysLog.class)){
                // 设置 operation（自己去定义 自定义注解）、方法名、模块名
                SysLog annotation = method.getAnnotation(SysLog.class);
                tblSysLog.setMethod(annotation.method());
                annotation.module();
                tblSysLog.setModule(annotation.module());
                tblSysLog.setOperation(annotation.operation());
                // 5 设置方法名、模块名
                //  RequestContextHolder 属于全局的用来获取request的类 包含整个项目中请求的对象
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = servletRequestAttributes.getRequest();
                //  获取当前的模块名称 ?
                String userName = getUserName(request.getSession(), annotation.module());
                tblSysLog.setOperator(userName);
            }else {
                return joinPoint.proceed() ;
            }
            // 原方法的执行
            proceed = joinPoint.proceed();
            // 设置方法的执行结果
            tblSysLog.setResult("成功");

        } catch (Throwable throwable) {
            // 出现异常的执行
            throwable.printStackTrace();
            tblSysLog.setResult("失败");
        }finally {
            //设置结束时间
            long endTime = System.currentTimeMillis() ;
            tblSysLog.setUseTime((int)(endTime - startTime));
        }
        sysLogService.insert(tblSysLog);
        return proceed ;
    }


    // 获取当前系统中登录的用户名称
    public String getUserName(HttpSession session , String module){
        // 系统中登录的用户分为3种  1.客户 2.司机 3.管理员  修改登录中的添加 session信息
        if (module.equals("后端管理")){
            Object adminName = session.getAttribute("adminName") ;
            // 判断一个值非空
            return adminName!=null&&adminName.toString().length()>0?"管理员:"+adminName:"管理员:未登录";
        }else if (module.equals("乘客端")){
            Object customerName = session.getAttribute("customerName");
            return customerName!=null&&customerName.toString().length()>0?"乘客:"+customerName:"乘客:未登录";
        }else if (module.equals("司机端")){
            Object driverName = session.getAttribute("driverName");
            return driverName!=null&&driverName.toString().length()>0?"司机:"+driverName:"司机:未登录";
        }else {
            return "未知";
        }
    }
}
